//
// File:	BaseEntity.cpp
// Author:	Thomas TISSOT-DUPONT
// Login:	<thomas.tissotdupont@free.fr>
//
// Create:	27/01/2010 at 17:58:56
// Purpose:	
//
#include "Base.hpp"
#include "BaseEntity.hpp"
#include "Trace.hpp"

//------------------------------------------------------------------
// Constructor / Destructor
//------------------------------------------------------------------
BaseEntity::BaseEntity()
	:	m_classname(),
		m_bRemoved(false),
		m_vfPosition(0, 0),
		m_vfFollowOffset(0, 0),
		m_vfSize(0, 0),
		m_vfVelocity(0, 0),
		m_pFollow(NULL),
		m_renderGroup(RENDERGROUP_UNKNOWN),
		m_pAnimating(NULL)
{
}

BaseEntity::~BaseEntity()
{
	delete m_pAnimating;
}

//------------------------------------------------------------------
// Class Name
//------------------------------------------------------------------
const std::string &BaseEntity::GetClassname() const
{
	return m_classname;
}

void BaseEntity::SetClassname(const std::string &name)
{
	m_classname = name;
}

//------------------------------------------------------------------
// Create / Destroy
//------------------------------------------------------------------
void BaseEntity::OnCreate()
{
	emit OnCreated(this);
}

void BaseEntity::OnDestroy()
{
}

//------------------------------------------------------------------
// DataMap
//------------------------------------------------------------------
void BaseEntity::OnCreateDataMap()
{
	DECLARE_DATAMAP_FIELD("x",				m_vfPosition.x,			0.0f);
	DECLARE_DATAMAP_FIELD("y",				m_vfPosition.y,			0.0f);
	DECLARE_DATAMAP_FIELD("width",			m_vfSize.x,				0.0f);
	DECLARE_DATAMAP_FIELD("height",			m_vfSize.y,				0.0f);
	DECLARE_DATAMAP_FIELD("velocity_x",		m_vfVelocity.x,			0.0f);
	DECLARE_DATAMAP_FIELD("velocity_y",		m_vfVelocity.y,			0.0f);
}

void BaseEntity::WriteDataMapVariable(const std::string &name, const Variant &v)
{
	m_dataMap.Write(name, v);
}

//------------------------------------------------------------------
// LoadFromFile
//------------------------------------------------------------------
bool BaseEntity::LoadFromFile(const std::string &fileName)
{
	//Create animating if neccessary
	if (m_pAnimating == NULL)
		m_pAnimating = GlobalVariables::FactoryManager::Get().CreateAnimating();

	//Load from the file
	bool bSuccess = m_pAnimating->LoadFromFile(fileName);
	if (bSuccess)
	{
		SetWidth(static_cast<float>(GetAnimating()->GetFrameWidth()));
		SetHeight(static_cast<float>(GetAnimating()->GetFrameHeight()));
	}
	return bSuccess;
}

//------------------------------------------------------------------
// Update
//------------------------------------------------------------------
void BaseEntity::Update()
{
	emit OnUpdated(this);
}

//------------------------------------------------------------------
// Render
//------------------------------------------------------------------
void BaseEntity::Render()
{
	if (GetAnimating() != NULL)
		GetAnimating()->Render(m_vfPosition.x, m_vfPosition.y);
}

//------------------------------------------------------------------
// Create entity by name
//------------------------------------------------------------------
BaseEntity *BaseEntity::CreateEntityByName(const std::string &name)
{
	if (GlobalVariables::FactoryManager::Get().GetEntityFactory() == NULL)
		return NULL;
	return dynamic_cast<BaseEntity *>(GlobalVariables::FactoryManager::Get().GetEntityFactory()->CreateEntityByName(name));
}

//------------------------------------------------------------------
// Emit Sound
//------------------------------------------------------------------
ISound *BaseEntity::EmitSound(const std::string &filename, bool bRemoveOnDeath /* = false */, bool bFollow /* = false */, bool bSpatialization /* = true */)
{
	ISound *pSound = GlobalVariables::SoundManager::Get().CreateSound(filename);
	if (pSound != NULL)
	{
		pSound->SetX(GetCenterX());
		pSound->SetY(GetCenterY());
		pSound->SetSpatializable(bSpatialization);

		if (bFollow)			CONNECT_METHOD_1(pSound, OnUpdated, this, &BaseEntity::UpdateFollowingSound);
		if (bRemoveOnDeath)		CONNECT_METHOD_0(this,   OnRemoved, pSound, &ISound::Remove);
								CONNECT_METHOD_0(pSound, OnStopped, pSound, &ISound::Remove);
		
		pSound->Play();
	}
	return pSound;
}

//------------------------------------------------------------------
// Follow Sound
//------------------------------------------------------------------
void BaseEntity::UpdateFollowingSound(ISound *pSound)
{
	if (pSound)
	{
		pSound->SetX(GetCenterX());
		pSound->SetY(GetCenterY());
	}
}

//------------------------------------------------------------------
// Follow Entity
//------------------------------------------------------------------
void BaseEntity::FollowEntity(IEntity *pOther)
{
	m_pFollow = pOther;
}

IEntity *BaseEntity::GetFollowingEntity() const
{
	return m_pFollow;
}

void BaseEntity::SetFollowOffsetX(float flOffsetX)
{
	m_vfFollowOffset.x = flOffsetX;
}

void BaseEntity::SetFollowOffsetY(float flOffsetY)
{
	m_vfFollowOffset.y = flOffsetY;
}

void BaseEntity::SetFollowOffsetCenterX(float flOffsetCenterX)
{
	SetFollowOffsetX(flOffsetCenterX - GetWidth() * 0.5f);
}

void BaseEntity::SetFollowOffsetCenterY(float flOffsetCenterY)
{
	SetFollowOffsetY(flOffsetCenterY - GetHeight() * 0.5f);
}

float BaseEntity::GetFollowOffsetX() const
{
	return m_vfFollowOffset.x;
}

float BaseEntity::GetFollowOffsetY() const
{
	return m_vfFollowOffset.y;
}

//------------------------------------------------------------------
// Remove Entity
//------------------------------------------------------------------
bool BaseEntity::IsRemoved() const
{
	return m_bRemoved;
}

void BaseEntity::Remove()
{
	m_bRemoved = true;
	emit OnRemoved(this);
	GlobalVariables::EventManager::Get().DisconnectTarget(this);
	GlobalVariables::EventManager::Get().DisconnectCaller(this);
}

//------------------------------------------------------------------
// Render Group
//------------------------------------------------------------------
void BaseEntity::SetRenderGroup(RenderGroup renderGroup)
{
	m_renderGroup = renderGroup;
}

RenderGroup BaseEntity::GetRenderGroup() const
{
	return m_renderGroup;
}

//------------------------------------------------------------------
// Position X / Y
//------------------------------------------------------------------
void BaseEntity::SetX(float flX)
{
	m_vfPosition.x = flX;
}

void BaseEntity::SetY(float flY)
{
	m_vfPosition.y = flY;
}

float BaseEntity::GetX() const
{
	return m_vfPosition.x;
}

float BaseEntity::GetY() const
{
	return m_vfPosition.y;
}

//------------------------------------------------------------------
// Size  Width / Height
//------------------------------------------------------------------
void BaseEntity::SetWidth(float flWidth)
{
	m_vfSize.x = flWidth;
}

void BaseEntity::SetHeight(float flHeight)
{
	m_vfSize.y = flHeight;
}

float BaseEntity::GetWidth() const
{
	return m_vfSize.x;
}

float BaseEntity::GetHeight() const
{
	return m_vfSize.y;
}

//------------------------------------------------------------------
// Center X / Y
//------------------------------------------------------------------
void BaseEntity::SetCenterX(float flCenterX)
{
	m_vfPosition.x = flCenterX - 0.5f * m_vfSize.x;
}

void BaseEntity::SetCenterY(float flCenterY)
{
	m_vfPosition.y = flCenterY - 0.5f * m_vfSize.y;
}

float BaseEntity::GetCenterX() const
{
	return m_vfSize.x * 0.5f + m_vfPosition.x;
}

float BaseEntity::GetCenterY() const
{
	return m_vfSize.y * 0.5f + m_vfPosition.y;
}

//------------------------------------------------------------------
// Velocity
//------------------------------------------------------------------
void BaseEntity::SetVelocityX(float flVelocityX)
{
	m_vfVelocity.x = flVelocityX;
}

void BaseEntity::SetVelocityY(float flVelocityY)
{
	m_vfVelocity.y = flVelocityY;
}

float BaseEntity::GetVelocityX() const
{
	return m_vfVelocity.x;
}

float BaseEntity::GetVelocityY() const
{
	return m_vfVelocity.y;
}

//------------------------------------------------------------------
// Animating
//------------------------------------------------------------------
IAnimating *BaseEntity::GetAnimating() const
{
	return m_pAnimating;
}
